unit EntityDefinition;

interface

uses
  FieldDefinition, OmniXML;

type

  TStringArray = array of String;
  TStringArrays = array of TStringArray;

  TEntityDefinition = class
  private
    fName: String;
    fDName: String;
    fFields: TFieldDefinitions;
    fOuters: TFieldDefinitions;
    fInners: TFieldDefinitions;
    fPrimaryKeys: TStringArray;
  public
    constructor Create(aNode: IXMLNode);
    destructor Destroy(); override;
    procedure setName(aName: String);
    function getName(): String;
    procedure setDName(aName: String);
    function getDName(): String;
    function getFieldDefinitions(): TFieldDefinitions;
    procedure addFieldDefinition(aFieldDefinition: TFieldDefinition);
    function getOuters(): TFieldDefinitions;
    procedure addOuter(aField: TFieldDefinition);
    procedure prepareOuters(aNodeList: IXMLNodeList);
    function getInners(): TFieldDefinitions;
    procedure addInner(aField: TFieldDefinition);
    function getPrimaryKeys(): TStringArray;
    procedure addPrimaryKey(aVal: String);
  end;

  TEntityDefinitions = array of TEntityDefinition;

implementation

uses
  SysUtils;

{ TEntityDefinition }

procedure TEntityDefinition.addFieldDefinition(aFieldDefinition
  : TFieldDefinition);
begin
  SetLength(fFields, Length(fFields) + 1);
  fFields[High(fFields)] := aFieldDefinition;
end;

procedure TEntityDefinition.addInner(aField: TFieldDefinition);
begin
  SetLength(fInners, Length(fInners) + 1);
  fInners[High(fInners)] := aField;
end;

procedure TEntityDefinition.addOuter(aField: TFieldDefinition);
begin
  SetLength(fOuters, Length(fOuters) + 1);
  fOuters[High(fOuters)] := aField;
end;

procedure TEntityDefinition.addPrimaryKey(aVal: String);
begin
  SetLength(fPrimaryKeys, Length(fPrimaryKeys) + 1);
  fPrimaryKeys[High(fPrimaryKeys)] := aVal;
end;

constructor TEntityDefinition.Create(aNode: IXMLNode);
var
  fXMLParser: IXMLDocument;
  fields: IXMLNodeList;
  field: IXMLNode;
  iField: integer;
  fField: TFieldDefinition;
begin
  inherited Create();
  SetLength(fFields, 0);
  if (aNode.SelectSingleNode('name') = nil) then
  begin
    raise Exception.Create('Schema error: table name not defined');
  end;
  setName(Trim(aNode.SelectSingleNode('name').Text));
  if (aNode.SelectSingleNode('dName') <> nil) then
  begin
    setDName(Trim(aNode.SelectSingleNode('dName').Text));
  end;
  if (aNode.SelectSingleNode('fields') = nil) then
  begin
    raise Exception.Create('No fields defined for table ' + getName());
  end;
  fields := aNode.SelectSingleNode('fields').SelectNodes('field');
  for iField := 0 to fields.Length - 1 do
  Begin
    field := fields.Item[iField];
    fField := TFieldDefinition.Create(field, getName());
    if (fField.isPrimaryKey()) then
    begin
      addPrimaryKey(fField.getName());
    end;
    if (fField.isForeignKey()) then
    begin
      addInner(fField);
    end;
    addFieldDefinition(fField);
  End;
end;

destructor TEntityDefinition.Destroy;
begin

  inherited;
end;

function TEntityDefinition.getDName: String;
begin
  Result := fDName;
end;

function TEntityDefinition.getFieldDefinitions: TFieldDefinitions;
begin
  Result := fFields;
end;

function TEntityDefinition.getInners: TFieldDefinitions;
begin
  Result := fInners;
end;

function TEntityDefinition.getName: String;
begin
  Result := fName;
end;

function TEntityDefinition.getOuters: TFieldDefinitions;
begin
  Result := fOuters;
end;

function TEntityDefinition.getPrimaryKeys: TStringArray;
begin
  Result := fPrimaryKeys;
end;

procedure TEntityDefinition.prepareOuters(aNodeList: IXMLNodeList);
var
  iTable: integer;
  fields: IXMLNodeList;
  iField: integer;
  fField: TFieldDefinition;
begin
  for iTable := 0 to aNodeList.Length - 1 do
  Begin
    fields := aNodeList.Item[iTable].SelectSingleNode('fields')
      .SelectNodes('field');
    for iField := 0 to fields.Length - 1 do
    begin
      fField := TFieldDefinition.Create(fields.Item[iField], aNodeList.Item[iTable].SelectSingleNode('name').Text);
      if ((fField.isForeignKey()) AND (fField.getForeignKeyTable() = getName())) then
      begin
        addOuter(fField);
      end else begin
        fField.Free;
      end;
    end;
  End;
end;

procedure TEntityDefinition.setDName(aName: String);
begin
  fDName := aName;
end;

procedure TEntityDefinition.setName(aName: String);
begin
  fName := aName;
end;

end.
